package com.whynot.frame.auth.shiro.config;

import com.whynot.frame.auth.jwt.filter.JWTFilter;
import com.whynot.frame.auth.jwt.filter.JwtAuthenticationTokenFilter;
import com.whynot.frame.auth.shiro.cache.RedisCacheManager;
import com.whynot.frame.auth.shiro.interceptor.KickoutSessionControlInterceptor;
import com.whynot.frame.auth.shiro.realm.MyRealm;
import com.whynot.frame.auth.shiro.settings.ShiroSettings;
import com.whynot.frame.basic.util.SpringUtil;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.config.Ini;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.Ordered;


import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述: shiro在SpringBoot的基础配置:
 * 作者: chenyao
 * 日期: 2018-01-30.
 * 项目名称: curtain-whynot-shiro-jwt-server
 * 版本: 1.0.0
 * JDK: since 1.8
 */
@Configuration
//@EnableConfigurationProperties(ShiroSettings.class)
public class ShiroConfig {

    private static final String SHIRO_URL = "shiro.ini";

    /* @Autowired
    private MyRealm myRealm;

    @Autowired
    private JWTFilter jwtFilter;*/

    @Bean("securityManager")
    public DefaultWebSecurityManager getManager() {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        MyRealm realm = getShiroRealm();

        //使用自己的realm
        manager.setRealm(realm);

        //设置缓存
        manager.setCacheManager(getCacheManager());
        realm.setAuthenticationCachingEnabled(true);
        realm.setAuthenticationCacheName("authenticationCache");
        realm.setAuthorizationCacheName("authorizationCache");
        realm.setAuthorizationCachingEnabled(true);

        //设置加密
        /*HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("Md5");
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        credentialsMatcher.setHashIterations(1);
        realm.setCredentialsMatcher(credentialsMatcher);*/

        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        manager.setSubjectDAO(subjectDAO);

        //设置Session会话管理器
        //manager.setSessionManager(sessionManager());

        return manager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager) {

        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<>();
        filterMap.put("jwt", new JWTFilter());
        filterMap.put("authCurrentUser",new JwtAuthenticationTokenFilter());
        factoryBean.setFilters(filterMap);

        //设置securityManager
        factoryBean.setSecurityManager(securityManager);

        //设置shiro必备的url
        factoryBean.setUnauthorizedUrl(shiroSettings().getUnauthorizedUrl());//设置没有权限匿名访问
        factoryBean.setLoginUrl(shiroSettings().getLoginUrl());//设置登陆url
        factoryBean.setSuccessUrl(shiroSettings().getSuccessUrl());//设置登陆成功后的url

        /*
         * 自定义url规则
         * http://shiro.apache.org/web.html#urls-
         */
        /*Map<String,String> map = new LinkedHashMap<String, String>();
        map.put("/login","anon");
        map.put("/401","anon");
        map.put("/**","jwt,kickout");
        factoryBean.setFilterChainDefinitionMap(map);*/
        factoryBean.setFilterChainDefinitionMap(setConfigLocation(SHIRO_URL));
        return factoryBean;
    }

    /**
     * 自定义sessionManager
     * @return
     */
    /*@Bean
    public SessionManager sessionManager(){
        DefaultWebSessionManager shiroSessionManager = new DefaultWebSessionManager();
        //这里可以不设置。Shiro有默认的session管理。如果缓存为Redis则需改用Redis的管理
        shiroSessionManager.setSessionDAO(getSessionDao());
        shiroSessionManager.setGlobalSessionTimeout(1800000);
        shiroSessionManager.setSessionIdCookieEnabled(true);
        return shiroSessionManager;
    }*/

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor(Ordered.LOWEST_PRECEDENCE);
    }

    /**
     * 下面的代码是添加注解支持
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     *  开启shiro aop注解支持.
     *  使用代理方式;所以需要开启代码支持;
     *  @param securityManager
     *  @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

   /* @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public JWTFilter getJwtFilter(){
        return new JWTFilter();
    }*/

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public MyRealm getShiroRealm(){
        return new MyRealm();
    }

    /*@Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public CachingSessionDAO getSessionDao(){
        return new CachingShiroSessionDao();
    }*/

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public CacheManager getCacheManager(){
        return new RedisCacheManager();
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroSettings shiroSettings(){
        return new ShiroSettings();
    }

    /**
     * 从指定路径加载shiro url的配置
     */
    private Ini.Section setConfigLocation(String configLocation) {
        Ini ini =  Ini.fromResourcePath(ResourceUtils.CLASSPATH_PREFIX + configLocation) ;
        Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
        if (CollectionUtils.isEmpty(section)) {
            section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        }
        return section;
    }
}
